// TODO: Maybe split off create and cutoff from _ROC/ to their own directories.


// STL
#include <iostream>                    // std::cerr, ::endl
#include <string>                      // std::string
#include <tuple>                       // std::tie()
#include <vector>                      // std::vector<>

// jScience
#include "jScience/stl/istream.hpp"    // read_file()

// stats++
#include "statsxx/postprocess/ROC.hpp" // ROC_pt, ROC_CostMatrix, calc_ROC_curve(), calc_ROC_curve_thresh_avg(), read_ROC_curve(), output_ROC_curve(), fit_binormal(), binormal_to_ROC(), map_scores(), AUC_binormal(), output_AUC()

// this
//#include "_ROC.hpp"                 // create_ROC(), cutoff_ROC()
#include "init.hpp"                    // read_param_file()


//
// USAGE: roc param_file
//
//     param_file :: parameters filename
//
//     =========================================================
//
// NOTE: See the example input for parameters.
//
int main(
         int argc,
         char* argv[]
         )
{
    //=========================================================
    // INITIALIZATION
    //=========================================================

    std::string filename_param = std::string(argv[1]);

    // ----- PARAMETERS -----
    std::string         ROC_file;
    // =====
    bool                create;
    // -----
    std::string         X_expected_file;
    std::string         X_predicted_file;
    // -----
    bool                thresh_avg;
    int                 nthresh;
    int                 ta_nROC;
    // =====
    bool                fit;
    // -----
    std::string         model;
    // -----
    int                 fit_nROC;
    // -----
    int                 model_npts;
    // =====
    bool                cutoff;
    // -----
    std::string         cutoff_method;
    // -----
    ROC_CostMatrix      cost_matrix;
    // =====
    std::string         prefix;
    std::tie(
             ROC_file,
             // =====
             create,
             // -----
             X_expected_file,
             X_predicted_file,
             // -----
             thresh_avg,
             nthresh,
             ta_nROC,
             // =====
             fit,
             // -----
             model,
             // -----
             fit_nROC,
             // -----
             model_npts,
             // =====
             cutoff,
             // -----
             cutoff_method,
             // -----
             cost_matrix,
             // =====
             prefix
             ) = read_param_file(
                                 filename_param
                                 );

    //=========================================================
    // CREATE (OR READ) ROC CURVE
    //=========================================================
    //
    // NOTE: This always occurs (create or read-in ROC).

    std::vector<ROC_pt> ROC;
    std::vector<ROC_pt> stddevROC;

    if( create )
    {
        std::vector<int> expected = read_file<int>(
                                                   X_expected_file
                                                   );

        std::vector<double> predicted = read_file<double>(
                                                          X_predicted_file
                                                          );

        ROC = calc_ROC_curve(
                             expected,
                             predicted
                             );

        // OUTPUT ROC CURVE
        std::string filename = prefix + ".ROC.dat";

        output_ROC_curve(
                         ROC,
                         // -----
                         filename
                         );


        if( thresh_avg )
        {
            // NOTE: Reuse ROC here.
            std::tie(
                     ROC,
                     stddevROC
                     ) = calc_ROC_curve_thresh_avg(
                                                   expected,
                                                   predicted,
                                                   // -----
                                                   nthresh,
                                                   ta_nROC
                                                   );

            // OUTPUT ROC CURVE
            std::string filename = prefix + ".ROC.thresh_avg.dat";

            output_ROC_curve(
                             ROC,
                             stddevROC,
                             // -----
                             filename
                             );
        }
    }
    // ... else read in
    else
    {
        std::tie(
                 ROC,
                 stddevROC
                 ) = read_ROC_curve(
                                    ROC_file
                                    );
    }

    //=========================================================
    // ESTIMATE (FIT) ROC CURVE
    //=========================================================

    if( fit )
    {
        std::vector<ROC_pt> fit_ROC;

        double              AUC;

        if( model == "binormal" )
        {
            // FIT CURVE
            bool                success;
            std::string         msg;
            double              a;
            double              b;
            std::tie(
                     success,
                     msg,
                     a,
                     b
                     ) = fit_binormal(
                                      ROC,
                                      stddevROC,
                                      // -----
                                      fit_nROC
                                      );

            fit_ROC = binormal_to_ROC(
                                      a,
                                      b,
                                      // -----
                                      model_npts
                                      );

            // CALCULATE AUC
            AUC = AUC_binormal(
                               a,
                               b
                               );
        }
        else if( model == "binormal_LR" )
        {
            // NOTE: See NOTEs above.

            bool                success;
            std::string         msg;
            double              d_a;
            double              c;
            std::tie(
                     success,
                     msg,
                     d_a,
                     c
                     ) = fit_binormal_LR(
                                         ROC,
                                         stddevROC,
                                         // -----
                                         fit_nROC
                                         );

            fit_ROC = binormal_LR_to_ROC(
                                         d_a,
                                         c,
                                         // -----
                                         model_npts
                                         );

            AUC = AUC_binormal_LR(
                                  d_a,
                                  c
                                  );
        }

        // MAP SCORES TO (FIT) ROC CURVE
        fit_ROC = map_scores(
                             ROC,
                             // -----
                             fit_ROC
                             );

        // OUTPUT
        std::string filename;

        // ... ROC CURVE
        filename = prefix + ".ROC.fit.dat";

        output_ROC_curve(
                         fit_ROC,
                         // -----
                         filename
                         );

        // ... AUC
        filename = prefix + ".ROC.fit.AUC.dat";

        output_AUC(
                   AUC,
                   // -----
                   filename
                   );
    }

    //=========================================================
    // FIND OPTIMAL OPERATING POINT ON ROC CURVE
    //=========================================================

    if( cutoff )
    {
        if( cutoff_method == "CB" )
        {
            bool   _success;
            double _cutoff;
            std::tie(
                     _success,
                     _cutoff
                     ) = cutoff_CB(
                                   ROC,
                                   // -----
                                   cost_matrix
                                   );

            if( _success )
            {
                // OUTPUT ROC CURVES
                std::string filename = prefix + ".ROC.cutoff.dat";

                output_cutoff(
                              _cutoff,
                              // -----
                              filename
                              );
            }
            else
            {
                std::cerr << "error in _ROC: could not determine cutoff" << std::endl;
            }
        }
        else if( cutoff_method == "weighted_NNM" )
        {
            // TODO: NOTE: This is a placeholder for the (potential) implementation of:
            //
            //     F. Habibzadeh, et al., ``On determining the most appropriate test cut-off value: the case of tests with continuous results,'' (2016).
        }


        // TODO: NOTE: If I add other cutoff methods (which I will), move the success checks and output here.
    }

    return 0;
}
